package com.tanhua.dubbo.server.HtMessageApi;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.PageUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.dubbo.config.annotation.Service;
import com.mongodb.client.result.UpdateResult;
import com.tanhua.dubbo.server.api.VideoApi;
import com.tanhua.dubbo.server.enums.HtTopState;
import com.tanhua.dubbo.server.enums.HtTotals;
import com.tanhua.dubbo.server.pojo.Publish;
import com.tanhua.dubbo.server.pojo.Video;
import com.tanhua.dubbo.server.vo.CommentType;
import com.tanhua.dubbo.server.vo.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.ArrayList;
import java.util.List;

@Service(version = "1.0.0")
@Slf4j
public class MessageApiImpl implements MessageApi {
    @Autowired
    private VideoApi videoApi;

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    //redis中消息状态的前缀
    private static final String TOTAL_COUNT_REDIS_KEY_PREFIX = "TOTAL_COUNT_";

    //redis中消息置顶的前缀
    private static final String TOTAL_TOP_REDIS_KEY_PREFIX = "TOTAL_TOP_";


    //获取redis中的键
    private String getRedisKey(HtTotals htTotals) {
        return TOTAL_COUNT_REDIS_KEY_PREFIX + htTotals;
    }

    /**
     * 修改动态的状态
     * 根据传过来的状态进行修改
     *
     * @param publishIds 选中的消息
     * @param htTotals   修改成什么状态
     * @return
     */
    @Override
    public Boolean ChangeStateOfPublish(List<String> publishIds, HtTotals htTotals) {
        List<ObjectId> list = new ArrayList<>();
        for (String publishId : publishIds) {
            list.add(new ObjectId(publishId));
        }
        //要修改的是哪些动态
        Query query = Query.query(Criteria.where("id").in(list));
        //需要修改的是内容
        Update update = Update.update("state", htTotals.getType());
        //修改
        UpdateResult result = this.mongoTemplate.updateMulti(query, update, Publish.class);
        long count = result.getModifiedCount();
        if (count > 0) {
            return true;
        }
//        }
//        if (htTotals.getType() != HtTotals.PEOPLE_CHECK.getType()) {
//
//            if (count > 0) {
//                String redisKey = getRedisKey(htTotals);
//                String checkRedisKey = getRedisKey(HtTotals.PEOPLE_CHECK);
//                redisTemplate.opsForValue().increment(redisKey, count);
//                redisTemplate.opsForValue().increment(checkRedisKey, -count);
//            }
//            return true;
//        } else {
//            for (ObjectId objectId : list) {
//                Query ckeckQuery = Query.query(Criteria.where("id").is(objectId));
//                Publish publish = mongoTemplate.findOne(ckeckQuery, Publish.class);
//                if (publish.getState() == 4) {
//                    String rejectRedisKey = getRedisKey(HtTotals.PEOPLE_REJECT);
//                    redisTemplate.opsForValue().increment(rejectRedisKey, -1);
//                } else {
//                    String rejectRedisKey = getRedisKey(HtTotals.PEOPLE_PASS);
//                    redisTemplate.opsForValue().increment(rejectRedisKey, -1);
//                }
//                String rejectRedisKey = getRedisKey(HtTotals.PEOPLE_CHECK);
//                redisTemplate.opsForValue().increment(rejectRedisKey, +1);
//                return true;
//            }
//        }
        return false;
    }

    /**
     * 修改动态置顶的状态
     *
     * @param publishId
     * @param htTopState
     * @return
     */
    @Override
    public Boolean ChangeIsTop(String publishId, HtTopState htTopState) {
        //先判断该动态是否是已置顶的,是置顶则修改非置顶
        String redisKey = TOTAL_TOP_REDIS_KEY_PREFIX;
        Boolean result = this.isTop(publishId);
        if (!result) {
            Query query = Query.query(Criteria.where("id").is(new ObjectId(publishId)));
            Update update = Update.update("topState", htTopState.getType());
            UpdateResult updateResult = this.mongoTemplate.updateMulti(query, update, Publish.class);
            //如果成功修改结果,设置redis缓存中的置顶数据
            if (updateResult.getModifiedCount() > 0) {
                redisTemplate.opsForHash().put(redisKey, publishId, "1");
            }
            return updateResult.getModifiedCount() > 0;
        }
        //如果不是置顶的则,修改置顶状态
        Query query = Query.query(Criteria.where("id").is(new ObjectId(publishId)));
        Update update = Update.update("topState", htTopState.getType());
        UpdateResult updateResult = this.mongoTemplate.updateMulti(query, update, Publish.class);
        //如果成功修改结果,删除redis缓存中的置顶数据
        if (updateResult.getModifiedCount() > 0) {
            redisTemplate.opsForHash().delete(redisKey, publishId);
        }
        //如果成功修改结果会修改记录为1条
        return updateResult.getModifiedCount() > 0;
    }

    /**
     * 判断该动态是否已经置顶
     *
     * @param publishId
     * @return
     */
    private Boolean isTop(String publishId) {
        //判定该动态的置顶状态是否为 2 (置顶)
        Query query = Query.query(Criteria.where("id").is(new ObjectId(publishId)).and("topState").is(2));
        Publish publish = this.mongoTemplate.findOne(query, Publish.class);
        //如果为空,则表示没有查到,那么我们返回一个false,表示不是置顶的
        if (ObjectUtil.isEmpty(publish)) {
            return false;
        }
        return true;
    }

    /**
     * 接口:
     * 查询publish列表（全部，或者按照审核状态）
     * 也可以通过消息id单独查询，也可以根据发布时间查询，也可以再时间范围类查询id
     *
     * @param pagesize  分页参数
     * @param page      分页参数
     * @param sortProp  排序字段
     * @param sortOrder 排序方式：ascending 升序 descending 降序
     * @param id        消息id(动态id)
     * @param sd        开始时间
     * @param ed        结束时间
     * @param uid       当前登录者的id（后台管理员id）
     * @param htTotals  审核状态（已经在service层中对其处理过了，全部：无，3，4，5--待审核，已拒绝，已通过，）
     * @return 消息列表
     */
    @Override
    public PageInfo<Publish> findPublishList(Integer page, Integer pagesize, String sortProp, String sortOrder,
                                             String id, Long sd, Long ed, String uid, HtTotals htTotals) {
        PageInfo<Publish> pageInfo = new PageInfo<>();
//        分页参数
        pageInfo.setPageNum(page);
        pageInfo.setPageSize(pagesize);
//        判断必须参数是否给齐
        if (!ObjectUtil.isAllNotEmpty(page, pagesize, sortProp, sortOrder, htTotals)) {
            log.error("用户" + uid + "查询消息列表参数缺失");
            return pageInfo;
        }
        PageRequest pageRequest = PageRequest.of(page - 1, pagesize);
        Query query = new Query();
        //query.with(pageRequest);
//        添加审核状态条件
        if (htTotals.getType() != 0) {
            query.addCriteria(Criteria.where("state").is(htTotals.getType()));
        }
//        判断是否要根据时间查询,起始与终止时间必须同时有
        if (ObjectUtil.isAllNotEmpty(sd, ed)) {
//            添加时间条件
            query.addCriteria(Criteria.where("created").gte(sd).lte(ed));

        }
//      判断是否要根据id查询
        if (StrUtil.isNotEmpty(id)) {
            query.addCriteria(Criteria.where("userId").is(Convert.toLong(id)));
        }
//        判断是否需要用uid查询
        if (uid != null) {
            query.addCriteria(Criteria.where("userId").is(Convert.toLong(uid)));
        }
//      排序
        List<Publish> publishList = null;
        if ("createDate".equals(sortProp)) {
            if ("ascending".equals(sortOrder)) {
                query.with(Sort.by(Sort.Order.asc("created")));
            } else {
                query.with(Sort.by(Sort.Order.desc("created")));
            }
            //查找符合条件的数据
            publishList = mongoTemplate.find(query, Publish.class);
            //将集合中存在置顶的数据放在最前面,生成新集合
            publishList = this.getAllOkPublish(publishList);
            //手动分页
            int[] ints = PageUtil.transToStartEnd(page - 1, pagesize);
            List<Publish> publishes = new ArrayList<>();
            //将需要的数据加到新集合中
            for (int i = ints[0]; i < Math.min(publishList.size(), ints[1]); i++) {
                publishes.add(publishList.get(i));
            }
            pageInfo.setRecords(publishes);
            //查询数量
            long count = mongoTemplate.count(query, Publish.class);
            pageInfo.setTotal(Convert.toInt(count));
            return pageInfo;

        } else {
            switch (sortProp) {
                case "reportCount":
                    //查询按照举报数排序的数据集合
                    publishList = videoApi.getPublishCommentLists(Convert.toLong(uid), CommentType.REPORT);
                    break;
                case "likeCount":
                    //查询按照点赞数排序的数据集合
                    publishList = videoApi.getPublishCommentLists(Convert.toLong(uid), CommentType.LIKE);
                    break;
                case "commentCount":
                    //查询按照评论数排序的数据集合
                    publishList = videoApi.getPublishCommentLists(Convert.toLong(uid), CommentType.COMMENT);
                    break;
                case "forwardingCount":
                    //查询按照转发数排序的数据集合
                    publishList = videoApi.getPublishCommentLists(Convert.toLong(uid), CommentType.TRANSMIT);
                    break;
            }
        }
        //将集合中存在置顶的数据放在最前面,生成新集合
        publishList = this.getAllOkPublish(publishList);
        if (StrUtil.equals("ascending", sortOrder)) {
            //手动分页
            int[] ints = PageUtil.transToStartEnd(page - 1, pagesize);
            //创建新集合
            List<Publish> publishes = new ArrayList<>();
            //获取自己需要的新数据
            for (int i = ints[0]; i < Math.min(publishList.size(), ints[1]); i++) {
                publishes.add(publishList.get(i));
            }
            //设置结果数据
            long count = mongoTemplate.count(query, Publish.class);
            pageInfo.setTotal(Convert.toInt(count));
            pageInfo.setRecords(publishes);
            return pageInfo;
        } else {
            //创建新集合
            List<Publish> list = new ArrayList<>();
            //倒序排列
            for (int i = publishList.size() - 1; i >= 0; i--) {
                Publish publish = publishList.get(i);
                list.add(publish);
            }
            //将集合中存在置顶的数据放在最前面,生成新集合
            list = this.getAllOkPublish(list);
            //手动分页
            int[] ints = PageUtil.transToStartEnd(page - 1, pagesize);
            List<Publish> publishes = new ArrayList<>();
            //获取自己需要的新数据
            for (int i = ints[0]; i < Math.min(list.size(), ints[1]); i++) {
                publishes.add(list.get(i));
            }
            //设置结果
            pageInfo.setRecords(publishes);

        }
        //查询数量
        long count = mongoTemplate.count(query, Publish.class);
        pageInfo.setTotal(Convert.toInt(count));
        return pageInfo;
    }


    /**
     * 接口：根据状态的种类，查询其数量
     *
     * @param htTotals 种类（枚举）
     * @return 数量
     */
    @Override
    public Long findTotalsCount(HtTotals htTotals,String uid,String id,Long startTime,Long stopTime) {
        //////        从reids中查询
//        String redisKey = getRedisKey(htTotals);
//        String redisCount = redisTemplate.opsForValue().get(redisKey);
////        如果redis中没有的话，从mongodb中查询
//        if (!StrUtil.isEmpty(redisCount)) {
//            return Convert.toLong(redisCount);
//        }
        ////        写进redis中
//        redisTemplate.opsForValue().set(redisKey, Convert.toStr(count));

        long count = 0L;

//        当两者都是null的情况下是全部列表展示
        if(ObjectUtil.isAllEmpty(uid,id)){
            Query query = new Query();
            if(htTotals.getType()!=0) {
                query.addCriteria(Criteria.where("state").is(htTotals.getType()));
            }
            if(ObjectUtil.isAllNotEmpty(startTime,stopTime)){
                query.addCriteria(Criteria.where("created").gte(startTime).lte(stopTime));
            }
            count = mongoTemplate.count(query, Publish.class);
        }


//        当id不为null,uid为null,是关键字查询
        if(StrUtil.isEmpty(uid)&&StrUtil.isNotEmpty(id)){
            Query query = new Query();
            query.addCriteria(Criteria.where("userId").is(Convert.toLong(id)));
            if(htTotals.getType()!=0) {
                query.addCriteria(Criteria.where("state").is(htTotals.getType()));
            }
            if(ObjectUtil.isAllNotEmpty(startTime,stopTime)){
                query.addCriteria(Criteria.where("created").gte(startTime).lte(stopTime));
            }
            count = mongoTemplate.count(query, Publish.class);
        }


//        当id不为null,uid为null,是通过id查询
        if(StrUtil.isEmpty(id)&&StrUtil.isNotEmpty(uid)) {
            Query query = new Query();
            query.addCriteria(Criteria.where("userId").is(Convert.toLong(uid)));
            if(htTotals.getType()!=0) {
                query.addCriteria(Criteria.where("state").is(htTotals.getType()));
            }
            if(ObjectUtil.isAllNotEmpty(startTime,stopTime)){
                query.addCriteria(Criteria.where("created").gte(startTime).lte(stopTime));
            }
            count = mongoTemplate.count(query, Publish.class);
        }
        return count;
    }


    @Override
    public Long findUserPublishCount(Long userId) {
        Query query = new Query();
        query.addCriteria(Criteria.where("userId").is(userId));
        long count = mongoTemplate.count(query, Publish.class);
        return count;
    }

    /**
     * 通过动态ID查询publish
     *
     * @param publishId
     * @return
     */
    @Override
    public Publish queryPbublishDetails(String publishId) {
        if (ObjectUtil.isEmpty(publishId)) {
            return null;
        }
        Query query = Query.query(Criteria.where("id").is(new ObjectId(publishId)));
        Publish publish = this.mongoTemplate.findOne(query, Publish.class);
        return publish;
    }

    /**
     * 将集合中存在置顶的数据放在最前面
     *
     * @param
     * @return
     */
    public List<Publish> getAllOkPublish(List<Publish> publishes) {
        //新建集合
        List<Publish> list = new ArrayList<>();
        //redis中消息置顶的前缀
        String redisKey = TOTAL_TOP_REDIS_KEY_PREFIX;
        for (int i = 0; i < publishes.size(); i++) {

            //判断redis缓存中是否有publishId置顶
            String publishId = publishes.get(i).getId().toHexString();
            Boolean result = redisTemplate.opsForHash().hasKey(redisKey, publishId);
            //将置顶的动态信息优先存入集合中
            if (result) {
                list.add(publishes.get(i));
                publishes.remove(i);
                i--;
            }
        }
        //将所有不是置顶的动态信息一次传入list集合中
        for (Publish publish : publishes) {
            list.add(publish);
        }
        return list;
    }

}
